#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <iptables.h>

#include <stdlib.h>
#include <string.h>

#include "ipt_ipcontext.h"

/* parseArguments() and final_check_Args() are in parseArgs.c */
int parseArguments(int c, char **argv, unsigned int *flags, struct ipt_entry_match **match);
void final_check_Args(unsigned int flags);


 /* Function which prints out usage message. */
static void help(void)                                                                                                                                                                                                   
{                                                                                                                                                                                                                        
       printf (                                                                                                                                                                                                              
"IPCONTEXT v%s options:\n\
                       \n\
   OPTIONS:            \n\
   =======             \n\
     --ipcontext_log                       set logger on           [default:OFF]     \n\
     --ipcontext_port      <port>          port that will be checked           \n\
     --ipcontext_protocol  <protocol>      protocol aspected at specified port \n\
     --ipcontext_regexp    <regexp>        regexp of selected protocol         \n\
     --ipcontext_dir <0|1>           direction: 0 - OUTPUT, 1 - INPUT [default:OUTPUT]  \n\
\n", IPTABLES_VERSION                                                                                                                                                                                       
             );                                                                                                                                                                                                              
}                                                                                                                                                                                                                        

/* Saves the match info in parsable form to stdout. */
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
{
	const struct ipt_context_info *info = (const struct ipt_context_info *)match->data;
	if( IS_LOG(info) ) {
		printf(" --ipcontext_log  ");
	}
	printf(" --ipcontext_port %d "    , info->port       );
	printf(" --ipcontext_protocol %s ", info->protocol   );
	printf(" --ipcontext_regexp \"%s\" "  , info->regular_exp);
	printf(" --ipcontext_dir %s  "  , IS_DIRECTION_IN(info) ? " 1 " : " 0 ");
}      
                          

/* Prints out the match  info */
static void print(const struct ipt_ip *ip,
                  const struct ipt_entry_match *match,
                  int numeric)
{
   const struct ipt_context_info *info = (const struct ipt_context_info *)match->data;
//   printf (     "%d. port=%d, direction=%s, protocol=%s, regexp=%s, log is %s", 
//                                   numeric,
//                                   info->port,
//                                   (IS_DIRECTION_IN(info) )? " INPUT " : " OUPUT ",
//                                   info->protocol,
//                                   info->regular_exp,
//                                   IS_LOG(info) ? " on" : "off" );   
	printf (     "%d. port=%d, direction=%s, protocol=%s,log %s", 
                                   numeric,
                                   info->port,
                                   (IS_DIRECTION_IN(info) )? " INPUT " : " OUPUT ",
                                   info->protocol,
                                   IS_LOG(info) ? " on" : "off" );                              
         
}                           
                            
                            
/* final check function     
This function is a kind of last chance for sanity check. It's called when the user enter a new rule, right after arguments parsing is done.
*/
static void final_check(unsigned int flags)
{
	final_check_Args(flags);
}

/* used for getopt_long() which runs and for each flag calls to parse() */
static struct option opts[] = {
	{.name = "ipcontext_port"       , .has_arg = 1, .flag = 0, .val = '1'},
	{.name = "ipcontext_protocol"   , .has_arg = 1, .flag = 0, .val = '2'},
	{.name = "ipcontext_log"        , .has_arg = 0, .flag = 0, .val = '3'},
	{.name = "ipcontext_regexp"     , .has_arg = 1, .flag = 0, .val = '4'},	
	{.name = "ipcontext_dir" 	, .has_arg = 1, .flag = 0, .val = '5'},
};

/* This function calls for  parseArguments 				     */
/* The reason that parseArguments does all the job is because 		     */
/* by that way, we are able to do Unit Testing independent of the other code */
/* of the ipcontext/kernel						     */
static int parse(int c, char **argv, int invert, unsigned int *flags,
                 const struct ipt_entry *entry,
                 unsigned int *nfcache,
                 struct ipt_entry_match **match)
{
	return parseArguments(c, argv, flags, match);
} 


/*                                                                                                                                                                                                     
 *  This init function is used to set some specific stuff like the netfilter 
 *  cache system. It's not very important to know how exactly it works for now.                                                                     
*/


static void init(struct ipt_entry_match *m, unsigned int *nfcache)                                                                                                                                                       
{                                                                                                                                                                                                                       
   /* Can't cache this */                                                                                                                                                                                                
  // *nfcache |= NFC_UNKNOWN;                                                                                                                                                                                              
}    


static struct iptables_match ipcontext
= {

    .name            = "ipcontext",
    .version         = IPTABLES_VERSION,
    .size            = IPT_ALIGN(sizeof(struct ipt_context_info)),
    .userspacesize   = IPT_ALIGN(sizeof(struct ipt_context_info)),

/*  'Help' is called when a user enter 'iptables -m module -h'. 
 *  'Parse' is called when you enter a new rule, its duty is to validate the
 *   arguments. 
 *   In the case of 'print', its called by 'iptables -L' to show previously enterd
 *   rules.
 */
  
    .help            = &help,
    .init            = &init,
    .parse           = &parse,
    .final_check     = &final_check,
    .print           = &print,
    .save            = &save,
    .extra_opts      = opts
    
};


/*  The iptables infrastructure can support multiple shared libraries.
 *  Each library must register to iptables by calling 'register_match()',
 *  defined into <iptables/iptables.c>. 
 *  This function is called when the module is loaded by iptables. 
 *  For more information about it: 'man dlopen'.  
 */
void _init(void)
{
   register_match(&ipcontext);
}

